#include "FLASH.h"
#include "spi.h"
#include "main.h"

/* -------------------- CS 引脚定义 -------------------- */
#define W25QX_CS_LOW()     HAL_GPIO_WritePin(FLASH_NSS_GPIO_Port, FLASH_NSS_Pin, GPIO_PIN_RESET)
#define W25QX_CS_HIGH()    HAL_GPIO_WritePin(FLASH_NSS_GPIO_Port, FLASH_NSS_Pin, GPIO_PIN_SET)

/* -------------------- 指令定义 -------------------- */
#define W25Q_WriteEnable       0x06
#define W25Q_SectorErase       0x20
#define W25Q_ChipErase         0xC7
#define W25Q_PageProgram       0x02
#define W25Q_ReadStatusReg1    0x05
#define W25Q_JedecDeviceID     0x9F
#define W25Q_ReadData          0x03
#define W25Q_EnableReset       0x66
#define W25Q_ResetDevice       0x99

/* -------------------- JEDEC ID 定义 -------------------- */
#define W25QX_MANUFACTURER_ID  0xEF
#define W25QX_MEMORY_TYPE      0x40
#define W25QX_CAPACITY_ID      0x16

#define FLASH_SPI hspi2
/* -------------------- 内部函数声明 -------------------- */
static void W25QX_WriteEnable(void);
static void W25QX_WaitUntilReady(void);
static void W25QX_Reset(void);

/* =====================================================
 * 内部函数实现
 * ===================================================== */

/* 写使能 */
static void W25QX_WriteEnable(void)
{
    uint8_t cmd = W25Q_WriteEnable;
    W25QX_CS_LOW();
    HAL_SPI_Transmit(&FLASH_SPI, &cmd, 1, HAL_MAX_DELAY);
    W25QX_CS_HIGH();
}

/* 等待设备空闲（do...while 实现） */
static void W25QX_WaitUntilReady(void)
{
    uint8_t cmd = W25Q_ReadStatusReg1;
    uint8_t status;

    do
    {
        W25QX_CS_LOW();
        HAL_SPI_Transmit(&FLASH_SPI, &cmd, 1, HAL_MAX_DELAY);
        HAL_SPI_Receive(&FLASH_SPI, &status, 1, HAL_MAX_DELAY);
        W25QX_CS_HIGH();
    }
    while (status & 0x01);
}

/* 软件复位（0x66 + 0x99） */
static void W25QX_Reset(void)
{
    uint8_t cmd;

    cmd = W25Q_EnableReset;
    W25QX_CS_LOW();
    HAL_SPI_Transmit(&FLASH_SPI, &cmd, 1, HAL_MAX_DELAY);
    W25QX_CS_HIGH();

    cmd = W25Q_ResetDevice;
    W25QX_CS_LOW();
    HAL_SPI_Transmit(&FLASH_SPI, &cmd, 1, HAL_MAX_DELAY);
    W25QX_CS_HIGH();
		
		W25QX_WaitUntilReady();
}

/* =====================================================
 * 外部接口函数实现
 * ===================================================== */

/* 初始化函数（返回 0=成功, 1=失败） */
uint8_t W25QX_Init(void)
{
    uint8_t cmd = W25Q_JedecDeviceID;
    uint8_t id[3] = {0};

    W25QX_CS_HIGH();

    /* 软件复位 */
    W25QX_Reset();

    /* 读取 JEDEC ID */
    W25QX_CS_LOW();
    HAL_SPI_Transmit(&FLASH_SPI, &cmd, 1, HAL_MAX_DELAY);
    HAL_SPI_Receive(&FLASH_SPI, id, 3, HAL_MAX_DELAY);
    W25QX_CS_HIGH();
		
		
    if (id[0] != W25QX_MANUFACTURER_ID ||
        id[1] != W25QX_MEMORY_TYPE ||
        id[2] != W25QX_CAPACITY_ID)
    {
        return 1; // 识别错误
    }

    return 0; // 成功
}

/* 整片擦除 */
void W25QX_ChipErase(void)
{
    uint8_t cmd = W25Q_ChipErase;

    W25QX_WriteEnable();

    W25QX_CS_LOW();
    HAL_SPI_Transmit(&FLASH_SPI, &cmd, 1, HAL_MAX_DELAY);
    W25QX_CS_HIGH();

    /* 擦除时间较长，需等待完成 */
    W25QX_WaitUntilReady();
}

/* 扇区擦除（支持多个扇区） */
void W25QX_SectorErase(uint32_t startSector, uint32_t sectorCount)
{
    uint8_t cmd[4];
    uint32_t addr;

    for (uint32_t s = 0; s < sectorCount; s++)
    {
        addr = (startSector + s) * W25QX_SECTOR_SIZE;

        W25QX_WriteEnable();

        cmd[0] = W25Q_SectorErase;
        cmd[1] = (addr >> 16) & 0xFF;
        cmd[2] = (addr >> 8) & 0xFF;
        cmd[3] = addr & 0xFF;

        W25QX_CS_LOW();
        HAL_SPI_Transmit(&FLASH_SPI, cmd, 4, HAL_MAX_DELAY);
        W25QX_CS_HIGH();

        W25QX_WaitUntilReady();
    }
}

/* 扇区写入（支持多个扇区） */
void W25QX_WriteSector(uint32_t startSector, uint32_t sectorCount, uint8_t *buf)
{
    uint32_t addr;
    uint32_t bufOffset = 0;
    uint8_t cmd[4];

    for (uint32_t s = 0; s < sectorCount; s++)
    {
        addr = (startSector + s) * W25QX_SECTOR_SIZE;

        for (uint16_t i = 0; i < (W25QX_SECTOR_SIZE / W25QX_PAGE_SIZE); i++)
        {
            W25QX_WriteEnable();

            cmd[0] = W25Q_PageProgram;
            cmd[1] = (addr >> 16) & 0xFF;
            cmd[2] = (addr >> 8) & 0xFF;
            cmd[3] = addr & 0xFF;

            W25QX_CS_LOW();
            HAL_SPI_Transmit(&FLASH_SPI, cmd, 4, HAL_MAX_DELAY);
            HAL_SPI_Transmit(&FLASH_SPI, buf + bufOffset, W25QX_PAGE_SIZE, HAL_MAX_DELAY);
            W25QX_CS_HIGH();

            W25QX_WaitUntilReady();

            addr += W25QX_PAGE_SIZE;
            bufOffset += W25QX_PAGE_SIZE;
        }
    }
}

/* 扇区读取（支持多个扇区） */
void W25QX_ReadSector(uint32_t startSector, uint32_t sectorCount, uint8_t *buf)
{
    uint8_t cmd[4];
    uint32_t addr = startSector * W25QX_SECTOR_SIZE;
    uint32_t totalBytes = sectorCount * W25QX_SECTOR_SIZE;

    cmd[0] = W25Q_ReadData;
    cmd[1] = (addr >> 16) & 0xFF;
    cmd[2] = (addr >> 8) & 0xFF;
    cmd[3] = addr & 0xFF;

    W25QX_CS_LOW();
    HAL_SPI_Transmit(&FLASH_SPI, cmd, 4, HAL_MAX_DELAY);
    HAL_SPI_Receive(&FLASH_SPI, buf, totalBytes, HAL_MAX_DELAY);
    W25QX_CS_HIGH();
}

/* 按地址读取任意长度数据 */
void W25QX_ReadData(uint32_t addr, uint8_t *buf, uint32_t len)
{
    uint8_t cmd[4];

    cmd[0] = W25Q_ReadData;
    cmd[1] = (addr >> 16) & 0xFF;
    cmd[2] = (addr >> 8) & 0xFF;
    cmd[3] = addr & 0xFF;

    W25QX_CS_LOW();
    HAL_SPI_Transmit(&FLASH_SPI, cmd, 4, HAL_MAX_DELAY);
    HAL_SPI_Receive(&FLASH_SPI, buf, len, HAL_MAX_DELAY);
    W25QX_CS_HIGH();
}
